﻿// Copyright (c) Vitaly Kamiansky. All rights reserved. 
// See License.txt in the project root.

using Property.Reloaders;
using Property.Workers;
using System;

namespace Property
{
    /// <summary>
    /// Contains words that extend the description 
    /// of the callbacks-based property value loading process.
    /// </summary>
    public static class FunctionWorkerPrototypeExtensionsCallbacks
    {
        /// <summary>
        /// ... diverting control to the specified handler if any exceptions are thrown ...
        /// </summary>
        /// <param name="handler">Tell me what to do if an error occurs.</param>
        /// <param name="testMode">Tell me if I have to ignore this word.</param>
        public static IFunctionWorkerPrototype<T> Catch<T>(this IFunctionWorkerPrototype<T> source, Action<Exception> handler, bool testMode = false)
        {
            return testMode ? source : new CatchFunctionWorkerDecoratorPrototype<T>(source, handler);
        }

        /// <summary>
        /// ... trying the specified number of times before throwing an exception ...
        /// </summary>
        /// <param name="retryCount">Tell me how many tries you give me to to get a value.</param>
        /// <param name="testMode">Tell me if I have to ignore this word.</param>
        public static IFunctionWorkerPrototype<T> Retry<T>(this IFunctionWorkerPrototype<T> source, int retryCount, bool testMode = false)
        {
            return testMode ? source : new RetryFunctionWorkerDecoratorPrototype<T>(source, retryCount);
        }

        /// <summary>
        /// <para>... (each time) ...</para>
        /// <para>( ! ) Don't forget to dispose of what you create with this word.</para>
        /// </summary>
        public static IReloaderPrototype<T> Each<T>(this IFunctionWorkerPrototype<T> source)
        {
            if (source == null) throw new ArgumentNullException("source");

            return new CallbackReloaderPrototype<T>(source);
        }

        /// <summary>
        /// <para>... first time ...</para>
        /// <para>( ! ) Don't forget to dispose of what you create with this word.</para>
        /// </summary>
        public static IReloaderPrototype<T> First<T>(this IFunctionWorkerPrototype<T> source)
        {
            return source.Each().First();
        }

        /// <summary>
        /// <para>... every odd time ...</para>
        /// <para>( ! ) Don't forget to dispose of what you create with this word.</para>
        /// </summary>
        public static IReloaderPrototype<T> Odd<T>(this IFunctionWorkerPrototype<T> source)
        {
            return source.Each().Odd();
        }

        /// <summary>
        /// <para>... if the specified condition is met (when) ...</para>
        /// <para>( ! ) Don't forget to dispose of what you create with this word.</para>
        /// </summary>
        /// <param name="condition">Tell me how to decide if the reload should happen.</param>
        public static IReloaderPrototype<T> Conditional<T>(this IFunctionWorkerPrototype<T> source, Func<bool> condition)
        {
            return source.Each().Conditional(condition);
        }

        /// <summary>
        /// <para>... if the discriminator state meets the specified condition (when) ...</para>
        /// <para>( ! ) Don't forget to dispose of what you create with this word.</para>
        /// </summary>
        /// <param name="getState">Tell me how the state should be produced 
        /// based on its previous value.</param>
        /// <param name="condition">Tell me how to use the state to decide if 
        /// the reload should happen.</param>
        public static IReloaderPrototype<T> Conditional<T, TState>(this IFunctionWorkerPrototype<T> source, Func<TState, TState> getState, Func<TState, bool> condition)
        {
            return source.Each().Conditional(getState, condition);
        }
    }
}
